home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / amiga / plotting / gnuplot3.lzh / gnuplot / setshow.c < prev    next >
C/C++ Source or Header  |  1991-09-04  |  63KB  |  2,602 lines

  1. /* GNUPLOT - setshow.c */
  2. /*
  3.  * Copyright (C) 1986, 1987, 1990, 1991   Thomas Williams, Colin Kelley
  4.  *
  5.  * Permission to use, copy, and distribute this software and its
  6.  * documentation for any purpose with or without fee is hereby granted, 
  7.  * provided that the above copyright notice appear in all copies and 
  8.  * that both that copyright notice and this permission notice appear 
  9.  * in supporting documentation.
  10.  *
  11.  * Permission to modify the software is granted, but not the right to
  12.  * distribute the modified code.  Modifications are to be distributed 
  13.  * as patches to released version.
  14.  *  
  15.  * This software is provided "as is" without express or implied warranty.
  16.  * 
  17.  *
  18.  * AUTHORS
  19.  * 
  20.  *   Original Software:
  21.  *     Thomas Williams,  Colin Kelley.
  22.  * 
  23.  *   Gnuplot 2.0 additions:
  24.  *       Russell Lang, Dave Kotz, John Campbell.
  25.  *
  26.  *   Gnuplot 3.0 additions:
  27.  *       Gershon Elber and many others.
  28.  * 
  29.  * Send your comments or suggestions to 
  30.  *  pixar!info-gnuplot@sun.com.
  31.  * This is a mailing list; to join it send a note to 
  32.  *  pixar!info-gnuplot-request@sun.com.  
  33.  * Send bug reports to
  34.  *  pixar!bug-gnuplot@sun.com.
  35.  */
  36.  
  37. #include <stdio.h>
  38. #include <math.h>
  39. #include "plot.h"
  40. #include "setshow.h"
  41.  
  42. #define DEF_FORMAT   "%g"    /* default format for tic mark labels */
  43. #define SIGNIF (0.01)        /* less than one hundredth of a tic mark */
  44.  
  45. /*
  46.  * global variables to hold status of 'set' options
  47.  *
  48.  */
  49. BOOLEAN            autoscale_r    = TRUE;
  50. BOOLEAN            autoscale_t    = TRUE;
  51. BOOLEAN            autoscale_u    = TRUE;
  52. BOOLEAN            autoscale_v    = TRUE;
  53. BOOLEAN            autoscale_x    = TRUE;
  54. BOOLEAN            autoscale_y    = TRUE;
  55. BOOLEAN            autoscale_z    = TRUE;
  56. BOOLEAN            autoscale_lt    = TRUE;
  57. BOOLEAN            autoscale_lu    = TRUE;
  58. BOOLEAN            autoscale_lv    = TRUE;
  59. BOOLEAN            autoscale_lx    = TRUE;
  60. BOOLEAN            autoscale_ly    = TRUE;
  61. BOOLEAN            autoscale_lz    = TRUE;
  62. BOOLEAN           clip_points    = FALSE;
  63. BOOLEAN           clip_lines1    = TRUE;
  64. BOOLEAN           clip_lines2    = FALSE;
  65. BOOLEAN            draw_border    = TRUE;
  66. BOOLEAN            draw_surface    = TRUE;
  67. BOOLEAN            timedate    = FALSE;
  68. char            dummy_var[MAX_NUM_VAR][MAX_ID_LEN+1] = { "x", "y" };
  69. char            xformat[MAX_ID_LEN+1] = DEF_FORMAT;
  70. char            yformat[MAX_ID_LEN+1] = DEF_FORMAT;
  71. char            zformat[MAX_ID_LEN+1] = DEF_FORMAT;
  72. enum            PLOT_STYLE data_style    = POINTS,
  73.             func_style    = LINES;
  74. BOOLEAN            grid        = FALSE;
  75. int                key            = -1;    /* default position */
  76. double            key_x, key_y, key_z;    /* user specified position for key */
  77. BOOLEAN            log_x        = FALSE,
  78.             log_y        = FALSE,
  79.             log_z        = FALSE;
  80. FILE*            outfile;
  81. char            outstr[MAX_ID_LEN+1] = "STDOUT";
  82. BOOLEAN            parametric    = FALSE;
  83. BOOLEAN            polar        = FALSE;
  84. int            angles_format    = ANGLES_RADIANS;
  85. int            mapping3d    = MAP3D_CARTESIAN;
  86. int            samples        = SAMPLES;
  87. int            iso_samples    = ISO_SAMPLES;
  88. float            xsize        = 1.0;  /* scale factor for size */
  89. float            ysize        = 1.0;  /* scale factor for size */
  90. float            zsize        = 1.0;  /* scale factor for size */
  91. float            surface_rot_z   = 30.0; /* Default 3d transform. */
  92. float            surface_rot_x   = 60.0;
  93. float            surface_scale   = 1.0;
  94. float            surface_zscale  = 1.0;
  95. int            term        = 0;        /* unknown term is 0 */
  96. char            term_options[MAX_ID_LEN+1] = "";
  97. char            title[MAX_LINE_LEN+1] = "";
  98. char            xlabel[MAX_LINE_LEN+1] = "";
  99. char            ylabel[MAX_LINE_LEN+1] = "";
  100. char            zlabel[MAX_LINE_LEN+1] = "";
  101. int            time_xoffset    = 0;
  102. int            time_yoffset    = 0;
  103. int            title_xoffset    = 0;
  104. int            title_yoffset    = 0;
  105. int            xlabel_xoffset    = 0;
  106. int            xlabel_yoffset    = 0;
  107. int            ylabel_xoffset    = 0;
  108. int            ylabel_yoffset    = 0;
  109. int            zlabel_xoffset    = 0;
  110. int            zlabel_yoffset    = 0;
  111. double            rmin        = -0.0,
  112.             rmax        =  10.0,
  113.             tmin        = -5.0,
  114.             tmax        =  5.0,
  115.             umin        = -5.0,
  116.             umax        = 5.0,
  117.             vmin        = -5.0,
  118.             vmax        = 5.0,
  119.             xmin        = -10.0,
  120.             xmax        = 10.0,
  121.             ymin        = -10.0,
  122.             ymax        = 10.0,
  123.             zmin        = -10.0,
  124.             zmax        = 10.0;
  125. double            loff        = 0.0,
  126.             roff        = 0.0,
  127.             toff        = 0.0,
  128.             boff        = 0.0;
  129. int            draw_contour    = CONTOUR_NONE;
  130. int            contour_pts    = 5;
  131. int            contour_kind    = CONTOUR_KIND_LINEAR;
  132. int            contour_order    = 4;
  133. int            contour_levels    = 5;
  134. double            zero = ZERO;            /* zero threshold, not 0! */
  135.  
  136. BOOLEAN xzeroaxis = TRUE;
  137. BOOLEAN yzeroaxis = TRUE;
  138.  
  139. BOOLEAN xtics = TRUE;
  140. BOOLEAN ytics = TRUE;
  141. BOOLEAN ztics = TRUE;
  142.  
  143. float ticslevel = 0.5;
  144.  
  145. struct ticdef xticdef = {TIC_COMPUTED};
  146. struct ticdef yticdef = {TIC_COMPUTED};
  147. struct ticdef zticdef = {TIC_COMPUTED};
  148.  
  149. BOOLEAN            tic_in        = TRUE;
  150.  
  151. struct text_label *first_label = NULL;
  152. struct arrow_def *first_arrow = NULL;
  153.  
  154. /*** other things we need *****/
  155. extern char *strcpy(),*strcat();
  156. extern int strlen();
  157. extern FILE *popen();
  158.  
  159. /* input data, parsing variables */
  160. extern struct lexical_unit token[];
  161. extern char input_line[];
  162. extern int num_tokens, c_token;
  163. extern BOOLEAN interactive;    /* from plot.c */
  164.  
  165. extern char replot_line[];
  166. extern struct udvt_entry *first_udv;
  167. extern BOOLEAN is_3d_plot;
  168.  
  169. extern double magnitude(),real();
  170. extern struct value *const_express();
  171.  
  172. /******** Local functions ********/
  173. static void set_xyzlabel();
  174. static void set_label();
  175. static void set_nolabel();
  176. static void set_arrow();
  177. static void set_noarrow();
  178. static void load_tics();
  179. static void load_tic_user();
  180. static void free_marklist();
  181. static void load_tic_series();
  182. static void load_offsets();
  183.  
  184. static void show_style(), show_range(), show_zero(), show_border();
  185. static void show_offsets(), show_output(), show_samples(), show_isosamples();
  186. static void show_view(), show_size(), show_title(), show_xlabel();
  187. static void show_angles();
  188. static void show_ylabel(), show_zlabel(), show_xzeroaxis(), show_yzeroaxis();
  189. static void show_label(), show_arrow(), show_grid(), show_key();
  190. static void show_polar(), show_parametric(), show_tics(), show_ticdef();
  191. static void show_time(), show_term(), show_plot(), show_autoscale(), show_clip();
  192. static void show_contour(), show_mapping(), show_format(), show_logscale();
  193. static void show_variables(), show_surface();
  194. static void delete_label();
  195. static int assign_label_tag();
  196. static void delete_arrow();
  197. static int assign_arrow_tag();
  198. static BOOLEAN set_one(), set_two(), set_three();
  199. static BOOLEAN show_one(), show_two();
  200.  
  201. /******** The 'set' command ********/
  202. void
  203. set_command()
  204. {
  205.     c_token++;
  206.  
  207.     if (!set_one() && !set_two() && !set_three())
  208.     int_error(
  209.     "valid set options:  'angles' '{no}arrow', {no}autoscale', \n\
  210.     '{no}border', '{no}clip', 'cntrparam', '{no}contour', 'data style', \n\
  211.     'dummy', 'format', 'function style', '{no}grid', 'isosamples', \n\
  212.     '{no}key', '{no}label', '{no}logscale', 'mapping', 'offsets', \n\
  213.     'output', '{no}parametric', '{no}polar', 'rrange', 'samples', \n\
  214.     'size', '{no}surface', 'terminal', 'tics', 'ticslevel', '{no}time', \n\
  215.     'title', 'trange', 'urange', 'view', 'vrange', 'xlabel', 'xrange', \n\
  216.     '{no}xtics', '{no}xzeroaxis', 'ylabel', 'yrange', '{no}ytics', \n\
  217.     '{no}yzeroaxis', 'zero', '{no}zeroaxis', 'zlabel', 'zrange', \n\
  218.     '{no}ztics'", c_token);
  219. }
  220.  
  221. /* return TRUE if a command match, FALSE if not */
  222. static BOOLEAN
  223. set_one()
  224. {
  225.     if (almost_equals(c_token,"ar$row")) {
  226.         c_token++;
  227.         set_arrow();
  228.     }
  229.     else if (almost_equals(c_token,"noar$row")) {
  230.         c_token++;
  231.         set_noarrow();
  232.     }
  233.      else if (almost_equals(c_token,"au$toscale")) {
  234.         c_token++;
  235.         if (END_OF_COMMAND) {
  236.            autoscale_r=autoscale_t = autoscale_x = autoscale_y = autoscale_z = TRUE;
  237.         } else if (equals(c_token, "xy") || equals(c_token, "yx")) {
  238.            autoscale_x = autoscale_y = TRUE;
  239.            c_token++;
  240.         } else if (equals(c_token, "r")) {
  241.            autoscale_r = TRUE;
  242.            c_token++;
  243.         } else if (equals(c_token, "t")) {
  244.            autoscale_t = TRUE;
  245.            c_token++;
  246.         } else if (equals(c_token, "x")) {
  247.            autoscale_x = TRUE;
  248.            c_token++;
  249.         } else if (equals(c_token, "y")) {
  250.            autoscale_y = TRUE;
  251.            c_token++;
  252.         } else if (equals(c_token, "z")) {
  253.            autoscale_z = TRUE;
  254.            c_token++;
  255.         }
  256.     } 
  257.     else if (almost_equals(c_token,"noau$toscale")) {
  258.         c_token++;
  259.         if (END_OF_COMMAND) {
  260.            autoscale_r=autoscale_t = autoscale_x = autoscale_y = autoscale_z = FALSE;
  261.         } else if (equals(c_token, "xy") || equals(c_token, "tyx")) {
  262.            autoscale_x = autoscale_y = FALSE;
  263.            c_token++;
  264.         } else if (equals(c_token, "r")) {
  265.            autoscale_r = FALSE;
  266.            c_token++;
  267.         } else if (equals(c_token, "t")) {
  268.            autoscale_t = FALSE;
  269.            c_token++;
  270.         } else if (equals(c_token, "x")) {
  271.            autoscale_x = FALSE;
  272.            c_token++;
  273.         } else if (equals(c_token, "y")) {
  274.            autoscale_y = FALSE;
  275.            c_token++;
  276.         } else if (equals(c_token, "z")) {
  277.            autoscale_z = FALSE;
  278.            c_token++;
  279.         }
  280.     } 
  281.     else if (almost_equals(c_token,"bor$der")) {
  282.         draw_border = TRUE;
  283.         c_token++;
  284.     }
  285.     else if (almost_equals(c_token,"nobor$der")) {
  286.         draw_border = FALSE;
  287.         c_token++;
  288.     }
  289.     else if (almost_equals(c_token,"c$lip")) {
  290.         c_token++;
  291.         if (END_OF_COMMAND)
  292.          /* assuming same as points */
  293.          clip_points = TRUE;
  294.         else if (almost_equals(c_token, "p$oints"))
  295.          clip_points = TRUE;
  296.         else if (almost_equals(c_token, "o$ne"))
  297.          clip_lines1 = TRUE;
  298.         else if (almost_equals(c_token, "t$wo"))
  299.          clip_lines2 = TRUE;
  300.         else
  301.          int_error("expecting 'points', 'one', or 'two'", c_token);
  302.         c_token++;
  303.     }
  304.     else if (almost_equals(c_token,"noc$lip")) {
  305.         c_token++;
  306.         if (END_OF_COMMAND) {
  307.            /* same as all three */
  308.            clip_points = FALSE;
  309.            clip_lines1 = FALSE;
  310.            clip_lines2 = FALSE;
  311.         } else if (almost_equals(c_token, "p$oints"))
  312.          clip_points = FALSE;
  313.         else if (almost_equals(c_token, "o$ne"))
  314.          clip_lines1 = FALSE;
  315.         else if (almost_equals(c_token, "t$wo"))
  316.          clip_lines2 = FALSE;
  317.         else
  318.          int_error("expecting 'points', 'one', or 'two'", c_token);
  319.         c_token++;
  320.     }
  321.     else if (almost_equals(c_token,"ma$pping3d")) {
  322.         c_token++;
  323.         if (END_OF_COMMAND)
  324.          /* assuming same as points */
  325.          mapping3d = MAP3D_CARTESIAN;
  326.         else if (almost_equals(c_token, "ca$rtesian"))
  327.          mapping3d = MAP3D_CARTESIAN;
  328.         else if (almost_equals(c_token, "s$pherical"))
  329.          mapping3d = MAP3D_SPHERICAL;
  330.         else if (almost_equals(c_token, "cy$lindrical"))
  331.          mapping3d = MAP3D_CYLINDRICAL;
  332.         else
  333.          int_error("expecting 'cartesian', 'spherical', or 'cylindrical'", c_token);
  334.         c_token++;
  335.     }
  336.     else if (almost_equals(c_token,"co$ntour")) {
  337.         c_token++;
  338.         if (END_OF_COMMAND)
  339.          /* assuming same as points */
  340.          draw_contour = CONTOUR_BASE;
  341.         else if (almost_equals(c_token, "ba$se"))
  342.          draw_contour = CONTOUR_BASE;
  343.         else if (almost_equals(c_token, "s$urface"))
  344.          draw_contour = CONTOUR_SRF;
  345.         else if (almost_equals(c_token, "bo$th"))
  346.          draw_contour = CONTOUR_BOTH;
  347.         else
  348.          int_error("expecting 'base', 'surface', or 'both'", c_token);
  349.         c_token++;
  350.     }
  351.     else if (almost_equals(c_token,"noco$ntour")) {
  352.         c_token++;
  353.         draw_contour = CONTOUR_NONE;
  354.     }
  355.     else if (almost_equals(c_token,"cntrp$aram")) {
  356.         struct value a;
  357.  
  358.         c_token++;
  359.         if (END_OF_COMMAND) {
  360.          /* assuming same as defaults */
  361.          contour_pts = 5;
  362.          contour_kind = CONTOUR_KIND_LINEAR;
  363.          contour_order = 4;
  364.          contour_levels = 5;
  365.         }
  366.         else if (almost_equals(c_token, "p$oints")) {
  367.          c_token++;
  368.          contour_pts = (int) real(const_express(&a));
  369.         }
  370.         else if (almost_equals(c_token, "li$near")) {
  371.          c_token++;
  372.          contour_kind = CONTOUR_KIND_LINEAR;
  373.         }
  374.         else if (almost_equals(c_token, "c$ubicspline")) {
  375.          c_token++;
  376.          contour_kind = CONTOUR_KIND_CUBIC_SPL;
  377.         }
  378.         else if (almost_equals(c_token, "b$spline")) {
  379.          c_token++;
  380.          contour_kind = CONTOUR_KIND_BSPLINE;
  381.         }
  382.         else if (almost_equals(c_token, "le$vels")) {
  383.          c_token++;
  384.          contour_levels = (int) real(const_express(&a));
  385.         }
  386.         else if (almost_equals(c_token, "o$rder")) {
  387.          int order;
  388.          c_token++;
  389.          order = (int) real(const_express(&a));
  390.          if ( order < 2 || order > 10 )
  391.              int_error("bspline order must be in [2..10] range.", c_token);
  392.          contour_order = order;
  393.         }
  394.         else
  395.          int_error("expecting 'linear', 'cubicspline', 'bspline', 'points', 'levels' or 'order'", c_token);
  396.         c_token++;
  397.     }
  398.     else if (almost_equals(c_token,"d$ata")) {
  399.         c_token++;
  400.         if (!almost_equals(c_token,"s$tyle"))
  401.             int_error("expecting keyword 'style'",c_token);
  402.         data_style = get_style();
  403.     }
  404.     else if (almost_equals(c_token,"d$ummy")) {
  405.         c_token++;
  406.         if (END_OF_COMMAND)
  407.             int_error("expecting dummy variable name", c_token);
  408.         else {
  409.             if (!equals(c_token,","))
  410.                 copy_str(dummy_var[0],c_token++);
  411.             if (!END_OF_COMMAND && equals(c_token,",")) {
  412.                 c_token++;
  413.                 if (END_OF_COMMAND)
  414.                     int_error("expecting second dummy variable name", c_token);
  415.                 copy_str(dummy_var[1],c_token++);
  416.                 }
  417.         }
  418.     }
  419.     else if (almost_equals(c_token,"fo$rmat")) {
  420.         BOOLEAN setx, sety, setz;
  421.         c_token++;
  422.         if (equals(c_token,"x")) {
  423.             setx = TRUE; sety = setz = FALSE;
  424.             c_token++;
  425.         }
  426.         else if (equals(c_token,"y")) {
  427.             setx = setz = FALSE; sety = TRUE;
  428.             c_token++;
  429.         }
  430.         else if (equals(c_token,"z")) {
  431.             setx = sety = FALSE; setz = TRUE;
  432.             c_token++;
  433.         }
  434.         else if (equals(c_token,"xy") || equals(c_token,"yx")) {
  435.             setx = sety = TRUE; setz = FALSE;
  436.             c_token++;
  437.         }
  438.         else if (isstring(c_token) || END_OF_COMMAND) {
  439.             /* Assume he wants all */
  440.             setx = sety = setz = TRUE;
  441.         }
  442.         if (END_OF_COMMAND) {
  443.             if (setx)
  444.                 (void) strcpy(xformat,DEF_FORMAT);
  445.             if (sety)
  446.                 (void) strcpy(yformat,DEF_FORMAT);
  447.             if (setz)
  448.                 (void) strcpy(zformat,DEF_FORMAT);
  449.         }
  450.         else {
  451.             if (!isstring(c_token))
  452.               int_error("expecting format string",c_token);
  453.             else {
  454.                 if (setx)
  455.                  quote_str(xformat,c_token);
  456.                 if (sety)
  457.                  quote_str(yformat,c_token);
  458.                 if (setz)
  459.                  quote_str(zformat,c_token);
  460.                 c_token++;
  461.             }
  462.         }
  463.     }
  464.     else if (almost_equals(c_token,"fu$nction")) {
  465.         c_token++;
  466.         if (!almost_equals(c_token,"s$tyle"))
  467.             int_error("expecting keyword 'style'",c_token);
  468.         func_style = get_style();
  469.     }
  470.     else if (almost_equals(c_token,"la$bel")) {
  471.         c_token++;
  472.         set_label();
  473.     }
  474.     else if (almost_equals(c_token,"nola$bel")) {
  475.         c_token++;
  476.         set_nolabel();
  477.     }
  478.     else if (almost_equals(c_token,"lo$gscale")) {
  479.         c_token++;
  480.         if (END_OF_COMMAND) {
  481.            log_x = log_y = log_z = TRUE;
  482.         } else {
  483.            if (chr_in_str(c_token, 'x'))
  484.                log_x = TRUE;
  485.            if (chr_in_str(c_token, 'y'))
  486.                log_y = TRUE;
  487.            if (chr_in_str(c_token, 'z'))
  488.                log_z = TRUE;
  489.            c_token++;
  490.         }
  491.     }
  492.     else if (almost_equals(c_token,"nolo$gscale")) {
  493.         c_token++;
  494.         if (END_OF_COMMAND) {
  495.         log_x = log_y = log_z = FALSE;
  496.         } else {
  497.         if (chr_in_str(c_token, 'x'))
  498.             log_x = FALSE;
  499.         if (chr_in_str(c_token, 'y'))
  500.             log_y = FALSE;
  501.         if (chr_in_str(c_token, 'z'))
  502.             log_z = FALSE;
  503.         c_token++;
  504.         }
  505.     } 
  506.     else if (almost_equals(c_token,"of$fsets")) {
  507.         c_token++;
  508.         if (END_OF_COMMAND) {
  509.             loff = roff = toff = boff = 0.0;  /* Reset offsets */
  510.         }
  511.         else {
  512.             load_offsets (&loff,&roff,&toff,&boff);
  513.         }
  514.     }
  515.     else
  516.         return(FALSE);    /* no command match */
  517.     return(TRUE);
  518. }
  519.  
  520.  
  521. /* return TRUE if a command match, FALSE if not */
  522. static BOOLEAN
  523. set_two()
  524. {
  525.      char testfile[MAX_LINE_LEN+1];
  526. #ifdef unix
  527.      static BOOLEAN pipe_open = FALSE;
  528. #endif
  529.  
  530.     if (almost_equals(c_token,"o$utput")) {
  531.         register FILE *f;
  532.  
  533.         c_token++;
  534.         if (term && term_init)
  535.             (*term_tbl[term].reset)();
  536.         if (END_OF_COMMAND) {    /* no file specified */
  537.              UP_redirect (4);
  538.             if (outfile != stdout) { /* Never close stdout */
  539. #ifdef unix
  540.                 if ( pipe_open ) {
  541.                     (void) pclose(outfile);
  542.                     pipe_open = FALSE;
  543.                 } else
  544. #endif
  545.                     (void) fclose(outfile);
  546.             }
  547.             outfile = stdout; /* Don't dup... */
  548.             term_init = FALSE;
  549.             (void) strcpy(outstr,"STDOUT");
  550.         } else if (!isstring(c_token))
  551.             int_error("expecting filename",c_token);
  552.         else {
  553.             quote_str(testfile,c_token);
  554. #ifdef unix
  555.             if ( *testfile == '|' ) {
  556.               if ((f = popen(testfile+1,"w")) == (FILE *)NULL)
  557.                 os_error("cannot create pipe; output not changed",c_token);
  558.               else
  559.                 pipe_open = TRUE;
  560.             } else
  561. #endif
  562.               if ((f = fopen(testfile,"w")) == (FILE *)NULL)
  563.                 os_error("cannot open file; output not changed",c_token);
  564.             if (outfile != stdout) /* Never close stdout */
  565.                 (void) fclose(outfile);
  566.             outfile = f;
  567.             term_init = FALSE;
  568.             outstr[0] = '\'';
  569.             (void) strcat(strcpy(outstr+1,testfile),"'");
  570.              UP_redirect (1);
  571.         }
  572.         c_token++;
  573.     }
  574.     else if (almost_equals(c_token,"tit$le")) {
  575.         set_xyzlabel(title,&title_xoffset,&title_yoffset);
  576.     }
  577.     else if (almost_equals(c_token,"xl$abel")) {
  578.         set_xyzlabel(xlabel,&xlabel_xoffset,&xlabel_yoffset);
  579.     }
  580.     else if (almost_equals(c_token,"yl$abel")) {
  581.         set_xyzlabel(ylabel,&ylabel_xoffset,&ylabel_yoffset);
  582.     }
  583.     else if (almost_equals(c_token,"zl$abel")) {
  584.         set_xyzlabel(zlabel,&zlabel_xoffset,&zlabel_yoffset);
  585.     }
  586.     else if (almost_equals(c_token,"xzero$axis")) {
  587.         c_token++;
  588.         xzeroaxis = TRUE;
  589.     } 
  590.     else if (almost_equals(c_token,"yzero$axis")) {
  591.         c_token++;
  592.         yzeroaxis = TRUE;
  593.     } 
  594.     else if (almost_equals(c_token,"zeroa$xis")) {
  595.         c_token++;
  596.         yzeroaxis = TRUE;
  597.         xzeroaxis = TRUE;
  598.     } 
  599.     else if (almost_equals(c_token,"noxzero$axis")) {
  600.         c_token++;
  601.         xzeroaxis = FALSE;
  602.     } 
  603.     else if (almost_equals(c_token,"noyzero$axis")) {
  604.         c_token++;
  605.         yzeroaxis = FALSE;
  606.     } 
  607.     else if (almost_equals(c_token,"nozero$axis")) {
  608.         c_token++;
  609.         xzeroaxis = FALSE;
  610.         yzeroaxis = FALSE;
  611.     } 
  612.     else if (almost_equals(c_token,"par$ametric")) {
  613.         if (!parametric) {
  614.            parametric = TRUE;
  615.            strcpy (dummy_var[0], "t");
  616.            strcpy (dummy_var[1], "y");
  617.              (void) fprintf(stderr,"\n\tdummy variable is t for curves, u/v for surfaces\n");
  618.         }
  619.         c_token++;
  620.     }
  621.     else if (almost_equals(c_token,"nopar$ametric")) {
  622.         if (parametric) {
  623.            parametric = FALSE;
  624.            strcpy (dummy_var[0], "x");
  625.            strcpy (dummy_var[1], "y");
  626.              (void) fprintf(stderr,"\n\tdummy variable is x for curves, x/y for surfaces\n");
  627.         }
  628.         c_token++;
  629.     }
  630.     else if (almost_equals(c_token,"pol$ar")) {
  631.         if (!polar) {
  632.             polar = TRUE;
  633.             if (parametric) {
  634.                 tmin = 0.0;
  635.                 tmax = 2*Pi;
  636.             } else if (angles_format == ANGLES_DEGREES) {
  637.                 xmin = 0.0;
  638.                 xmax = 360.0;
  639.             } else {
  640.                 xmin = 0.0;
  641.                 xmax = 2*Pi;
  642.             }
  643.         }
  644.         c_token++;
  645.     }
  646.     else if (almost_equals(c_token,"nopo$lar")) {
  647.         if (polar) {
  648.             polar = FALSE;
  649.             if (parametric) {
  650.                 tmin = -5.0;
  651.                 tmax = 5.0;
  652.             } else {
  653.                 xmin = -10.0;
  654.                 xmax = 10.0;
  655.             }
  656.         }
  657.         c_token++;
  658.     }
  659.     else if (almost_equals(c_token,"an$gles")) {
  660.         c_token++;
  661.         if (END_OF_COMMAND) {
  662.         /* assuming same as defaults */
  663.         angles_format = ANGLES_RADIANS;
  664.         }
  665.         else if (almost_equals(c_token, "r$adians")) {
  666.         angles_format = ANGLES_RADIANS;
  667.         c_token++;
  668.         }
  669.         else if (almost_equals(c_token, "d$egrees")) {
  670.         angles_format = ANGLES_DEGREES;
  671.         c_token++;
  672.         }
  673.         else
  674.          int_error("expecting 'radians' or 'degrees'", c_token);
  675.     }
  676.     else if (almost_equals(c_token,"g$rid")) {
  677.         grid = TRUE;
  678.         c_token++;
  679.     }
  680.     else if (almost_equals(c_token,"nog$rid")) {
  681.         grid = FALSE;
  682.         c_token++;
  683.     }
  684.     else if (almost_equals(c_token,"su$rface")) {
  685.         draw_surface = TRUE;
  686.         c_token++;
  687.     }
  688.     else if (almost_equals(c_token,"nosu$rface")) {
  689.         draw_surface = FALSE;
  690.         c_token++;
  691.     }
  692.     else if (almost_equals(c_token,"k$ey")) {
  693.         struct value a;
  694.         c_token++;
  695.         if (END_OF_COMMAND) {
  696.             key = -1;
  697.         } 
  698.         else {
  699.             key_x = real(const_express(&a));
  700.             if (!equals(c_token,","))
  701.                 int_error("',' expected",c_token);
  702.             c_token++;
  703.             key_y = real(const_express(&a));
  704.             if (equals(c_token,","))
  705.             {
  706.                     c_token++;
  707.                 key_z = real(const_express(&a));
  708.             }
  709.             key = 1;
  710.         } 
  711.     }
  712.     else if (almost_equals(c_token,"nok$ey")) {
  713.         key = 0;
  714.         c_token++;
  715.     }
  716.     else if (almost_equals(c_token,"tic$s")) {
  717.         tic_in = TRUE;
  718.         c_token++;
  719.         if (almost_equals(c_token,"i$n")) {
  720.             tic_in = TRUE;
  721.             c_token++;
  722.         }
  723.         else if (almost_equals(c_token,"o$ut")) {
  724.             tic_in = FALSE;
  725.             c_token++;
  726.         }
  727.     }
  728.      else if (almost_equals(c_token,"xt$ics")) {
  729.         xtics = TRUE;
  730.         c_token++;
  731.         if (END_OF_COMMAND) { /* reset to default */
  732.            if (xticdef.type == TIC_USER) {
  733.               free_marklist(xticdef.def.user);
  734.               xticdef.def.user = NULL;
  735.            }
  736.            xticdef.type = TIC_COMPUTED;
  737.         }
  738.         else
  739.          load_tics(&xticdef);
  740.     } 
  741.      else if (almost_equals(c_token,"noxt$ics")) {
  742.         xtics = FALSE;
  743.         c_token++;
  744.     } 
  745.      else if (almost_equals(c_token,"yt$ics")) {
  746.         ytics = TRUE;
  747.         c_token++;
  748.         if (END_OF_COMMAND) { /* reset to default */
  749.            if (yticdef.type == TIC_USER) {
  750.               free_marklist(yticdef.def.user);
  751.               yticdef.def.user = NULL;
  752.            }
  753.            yticdef.type = TIC_COMPUTED;
  754.         }
  755.         else
  756.          load_tics(&yticdef);
  757.     } 
  758.      else if (almost_equals(c_token,"noyt$ics")) {
  759.         ytics = FALSE;
  760.         c_token++;
  761.     } 
  762.      else if (almost_equals(c_token,"zt$ics")) {
  763.         ztics = TRUE;
  764.         c_token++;
  765.         if (END_OF_COMMAND) { /* reset to default */
  766.            if (zticdef.type == TIC_USER) {
  767.               free_marklist(zticdef.def.user);
  768.               zticdef.def.user = NULL;
  769.            }
  770.            zticdef.type = TIC_COMPUTED;
  771.         }
  772.         else
  773.          load_tics(&zticdef);
  774.     } 
  775.      else if (almost_equals(c_token,"nozt$ics")) {
  776.         ztics = FALSE;
  777.         c_token++;
  778.     } 
  779.     else if (almost_equals(c_token,"ticsl$evel")) {
  780.         double tlvl;
  781.         struct value a;
  782.  
  783.         c_token++;
  784.         tlvl = real(const_express(&a));
  785.         if (tlvl < 0.0)
  786.             int_error("tics level must be > 0; ticslevel unchanged",
  787.                 c_token);
  788.         else {
  789.             ticslevel = tlvl;
  790.         }
  791.     }
  792.     else
  793.     return(FALSE);    /* no command match */
  794.  
  795.     return(TRUE);
  796. }
  797.  
  798.  
  799.  
  800. /* return TRUE if a command match, FALSE if not */
  801. static BOOLEAN
  802. set_three()
  803. {
  804.      if (almost_equals(c_token,"sa$mples")) {
  805.         register int tsamp;
  806.         struct value a;
  807.  
  808.         c_token++;
  809.         tsamp = (int)magnitude(const_express(&a));
  810.         if (tsamp < 2)
  811.             int_error("sampling rate must be > 1; sampling unchanged",
  812.                 c_token);
  813.         else {
  814.                 extern struct surface_points *first_3dplot;
  815.             register struct surface_points *f_3dp = first_3dplot;
  816.  
  817.             first_3dplot = NULL;
  818.             sp_free(f_3dp);
  819.  
  820.             samples = tsamp;
  821.         }
  822.     }
  823.     else if (almost_equals(c_token,"isosa$mples")) {
  824.         register int tsamp;
  825.         struct value a;
  826.  
  827.         c_token++;
  828.         tsamp = (int)magnitude(const_express(&a));
  829.         if (tsamp < 2)
  830.             int_error("sampling rate must be > 1; sampling unchanged",
  831.                 c_token);
  832.         else {
  833.                 extern struct curve_points *first_plot;
  834.                 extern struct surface_points *first_3dplot;
  835.             register struct curve_points *f_p = first_plot;
  836.             register struct surface_points *f_3dp = first_3dplot;
  837.  
  838.             first_plot = NULL;
  839.             first_3dplot = NULL;
  840.             cp_free(f_p);
  841.             sp_free(f_3dp);
  842.  
  843.             iso_samples = tsamp;
  844.         }
  845.     }
  846.     else if (almost_equals(c_token,"si$ze")) {
  847.         struct value s;
  848.         c_token++;
  849.         if (END_OF_COMMAND) {
  850.             xsize = 1.0;
  851.             ysize = 1.0;
  852.         } 
  853.         else {
  854.                 xsize=real(const_express(&s));
  855.                 if (!equals(c_token,","))
  856.                     int_error("',' expected",c_token);
  857.                 c_token++;
  858.                 ysize=real(const_express(&s));
  859.         } 
  860.     } 
  861.     else if (almost_equals(c_token,"t$erminal")) {
  862.         c_token++;
  863.         if (END_OF_COMMAND) {
  864.             list_terms();
  865.             screen_ok = FALSE;
  866.         }
  867.         else {
  868.             if (term && term_init) {
  869.                 (*term_tbl[term].reset)();
  870.                 (void) fflush(outfile);
  871.             }
  872.             term = set_term(c_token);
  873.             c_token++;
  874.  
  875.             /* get optional mode parameters */
  876.             if (term)
  877.                 (*term_tbl[term].options)();
  878.             if (interactive && *term_options)
  879.                 fprintf(stderr,"Options are '%s'\n",term_options);
  880.         }
  881.     }
  882.     else if (almost_equals(c_token,"tim$e")) {
  883.         timedate = TRUE;
  884.         c_token++;
  885.         if (!END_OF_COMMAND) {
  886.             struct value a;
  887.             int x, y;
  888.  
  889.             /* We have x,y offsets specified */
  890.             if (!equals(c_token,","))
  891.                 time_xoffset = (int)real(const_express(&a));
  892.             if (!END_OF_COMMAND && equals(c_token,",")) {
  893.                 c_token++;
  894.                 time_yoffset = (int)real(const_express(&a));
  895.             }
  896.         }
  897.     }
  898.     else if (almost_equals(c_token,"not$ime")) {
  899.         timedate = FALSE;
  900.         c_token++;
  901.     }
  902.     else if (almost_equals(c_token,"rr$ange")) {
  903.          BOOLEAN changed;
  904.         c_token++;
  905.         if (!equals(c_token,"["))
  906.             int_error("expecting '['",c_token);
  907.         c_token++;
  908.         changed = load_range(&rmin,&rmax);
  909.         if (!equals(c_token,"]"))
  910.           int_error("expecting ']'",c_token);
  911.         c_token++;
  912.         if (changed)
  913.           autoscale_r = FALSE;
  914.     }
  915.     else if (almost_equals(c_token,"tr$ange")) {
  916.          BOOLEAN changed;
  917.         c_token++;
  918.         if (!equals(c_token,"["))
  919.             int_error("expecting '['",c_token);
  920.         c_token++;
  921.         changed = load_range(&tmin,&tmax);
  922.         if (!equals(c_token,"]"))
  923.           int_error("expecting ']'",c_token);
  924.         c_token++;
  925.         if (changed)
  926.           autoscale_t = FALSE;
  927.     }
  928.     else if (almost_equals(c_token,"ur$ange")) {
  929.          BOOLEAN changed;
  930.         c_token++;
  931.         if (!equals(c_token,"["))
  932.             int_error("expecting '['",c_token);
  933.         c_token++;
  934.         changed = load_range(&umin,&umax);
  935.         if (!equals(c_token,"]"))
  936.           int_error("expecting ']'",c_token);
  937.         c_token++;
  938.         if (changed)
  939.           autoscale_u = FALSE;
  940.     }
  941.     else if (almost_equals(c_token,"vi$ew")) {
  942.         int i;
  943.         BOOLEAN was_comma = TRUE;
  944.         double local_vals[4];
  945.         struct value a;
  946.  
  947.         local_vals[0] = surface_rot_x;
  948.         local_vals[1] = surface_rot_z;
  949.         local_vals[2] = surface_scale;
  950.         local_vals[3] = surface_zscale;
  951.         c_token++;
  952.         for (i = 0; i < 4 && !(END_OF_COMMAND);) {
  953.             if (equals(c_token,",")) {
  954.                 if (was_comma) i++;
  955.                 was_comma = TRUE;
  956.                 c_token++;
  957.             }
  958.             else {
  959.                 if (!was_comma)
  960.                     int_error("',' expected",c_token);
  961.                 local_vals[i] = real(const_express(&a));
  962.                 i++;
  963.                 was_comma = FALSE;
  964.             }
  965.         }
  966.  
  967.         if (local_vals[0] < 0 || local_vals[0] > 180)
  968.             int_error("rot_x must be in [0:180] degrees range; view unchanged",
  969.                   c_token);
  970.         if (local_vals[1] < 0 || local_vals[1] > 360)
  971.             int_error("rot_z must be in [0:360] degrees range; view unchanged",
  972.                   c_token);
  973.         if (local_vals[2] < 1e-6)
  974.             int_error("scale must be > 0; view unchanged", c_token);
  975.         if (local_vals[3] < 1e-6)
  976.             int_error("zscale must be > 0; view unchanged", c_token);
  977.  
  978.         surface_rot_x = local_vals[0];
  979.         surface_rot_z = local_vals[1];
  980.         surface_scale = local_vals[2];
  981.         surface_zscale = local_vals[3];
  982.     }
  983.     else if (almost_equals(c_token,"vr$ange")) {
  984.          BOOLEAN changed;
  985.         c_token++;
  986.         if (!equals(c_token,"["))
  987.             int_error("expecting '['",c_token);
  988.         c_token++;
  989.         changed = load_range(&vmin,&vmax);
  990.         if (!equals(c_token,"]"))
  991.           int_error("expecting ']'",c_token);
  992.         c_token++;
  993.         if (changed)
  994.           autoscale_v = FALSE;
  995.     }
  996.     else if (almost_equals(c_token,"xr$ange")) {
  997.          BOOLEAN changed;
  998.         c_token++;
  999.         if (!equals(c_token,"["))
  1000.             int_error("expecting '['",c_token);
  1001.         c_token++;
  1002.         changed = load_range(&xmin,&xmax);
  1003.         if (!equals(c_token,"]"))
  1004.           int_error("expecting ']'",c_token);
  1005.         c_token++;
  1006.         if (changed)
  1007.           autoscale_x = FALSE;
  1008.     }
  1009.     else if (almost_equals(c_token,"yr$ange")) {
  1010.          BOOLEAN changed;
  1011.         c_token++;
  1012.         if (!equals(c_token,"["))
  1013.             int_error("expecting '['",c_token);
  1014.         c_token++;
  1015.         changed = load_range(&ymin,&ymax);
  1016.         if (!equals(c_token,"]"))
  1017.           int_error("expecting ']'",c_token);
  1018.         c_token++;
  1019.         if (changed)
  1020.           autoscale_y = FALSE;
  1021.     }
  1022.     else if (almost_equals(c_token,"zr$ange")) {
  1023.          BOOLEAN changed;
  1024.         c_token++;
  1025.         if (!equals(c_token,"["))
  1026.             int_error("expecting '['",c_token);
  1027.         c_token++;
  1028.         changed = load_range(&zmin,&zmax);
  1029.         if (!equals(c_token,"]"))
  1030.           int_error("expecting ']'",c_token);
  1031.         c_token++;
  1032.         if (changed)
  1033.           autoscale_z = FALSE;
  1034.     }
  1035.     else if (almost_equals(c_token,"z$ero")) {
  1036.         struct value a;
  1037.         c_token++;
  1038.         zero = magnitude(const_express(&a));
  1039.     }
  1040.     else
  1041.         return(FALSE);    /* no command match */
  1042.     return(TRUE);
  1043. }
  1044.  
  1045. /*********** Support functions for set_command ***********/
  1046.  
  1047. /* process a 'set {x/y/z}label command */
  1048. /* set {x/y/z}label {label_text} {x}{,y} */
  1049. static void set_xyzlabel(str,xpos,ypos)
  1050. char *str;
  1051. int *xpos,*ypos;
  1052. {
  1053.     c_token++;
  1054.     if (END_OF_COMMAND) {    /* no label specified */
  1055.         str[0] = '\0';
  1056.     } else {
  1057.         if (isstring(c_token)) {
  1058.             /* We have string specified - grab it. */
  1059.             quotel_str(str,c_token);
  1060.             c_token++;
  1061.         }
  1062.         if (!END_OF_COMMAND) {
  1063.             struct value a;
  1064.             int x, y;
  1065.  
  1066.             /* We have x,y offsets specified */
  1067.             if (!equals(c_token,","))
  1068.                 *xpos = (int)real(const_express(&a));
  1069.             if (!END_OF_COMMAND && equals(c_token,",")) {
  1070.                 c_token++;
  1071.                 *ypos = (int)real(const_express(&a));
  1072.             }
  1073.         }
  1074.     }
  1075. }
  1076.  
  1077. /* process a 'set label' command */
  1078. /* set label {tag} {label_text} {at x,y} {pos} */
  1079. static void
  1080. set_label()
  1081. {
  1082.     struct value a;
  1083.     struct text_label *this_label = NULL;
  1084.     struct text_label *new_label = NULL;
  1085.     struct text_label *prev_label = NULL;
  1086.     double x, y, z;
  1087.     char text[MAX_LINE_LEN+1];
  1088.     enum JUSTIFY just;
  1089.     int tag;
  1090.     BOOLEAN set_text, set_position, set_just;
  1091.  
  1092.     /* get tag */
  1093.     if (!END_OF_COMMAND 
  1094.        && !isstring(c_token) 
  1095.        && !equals(c_token, "at")
  1096.        && !equals(c_token, "left")
  1097.        && !equals(c_token, "center")
  1098.        && !equals(c_token, "centre")
  1099.        && !equals(c_token, "right")) {
  1100.        /* must be a tag expression! */
  1101.        tag = (int)real(const_express(&a));
  1102.        if (tag <= 0)
  1103.         int_error("tag must be > zero", c_token);
  1104.     } else
  1105.      tag = assign_label_tag(); /* default next tag */
  1106.      
  1107.     /* get text */
  1108.     if (!END_OF_COMMAND && isstring(c_token)) {
  1109.        /* get text */
  1110.        quotel_str(text, c_token);
  1111.        c_token++;
  1112.        set_text = TRUE;
  1113.     } else {
  1114.        text[0] = '\0';        /* default no text */
  1115.        set_text = FALSE;
  1116.     }
  1117.      
  1118.     /* get justification - what the heck, let him put it here */
  1119.     if (!END_OF_COMMAND && !equals(c_token, "at")) {
  1120.        if (almost_equals(c_token,"l$eft")) {
  1121.           just = LEFT;
  1122.        }
  1123.        else if (almost_equals(c_token,"c$entre")
  1124.               || almost_equals(c_token,"c$enter")) {
  1125.           just = CENTRE;
  1126.        }
  1127.        else if (almost_equals(c_token,"r$ight")) {
  1128.           just = RIGHT;
  1129.        }
  1130.        else
  1131.         int_error("bad syntax in set label", c_token);
  1132.        c_token++;
  1133.        set_just = TRUE;
  1134.     } else {
  1135.        just = LEFT;            /* default left justified */
  1136.        set_just = FALSE;
  1137.     } 
  1138.  
  1139.     /* get position */
  1140.     if (!END_OF_COMMAND && equals(c_token, "at")) {
  1141.        c_token++;
  1142.        if (END_OF_COMMAND)
  1143.         int_error("coordinates expected", c_token);
  1144.        /* get coordinates */
  1145.        x = real(const_express(&a));
  1146.        if (!equals(c_token,","))
  1147.         int_error("',' expected",c_token);
  1148.        c_token++;
  1149.        y = real(const_express(&a));
  1150.        if (equals(c_token,",")) {
  1151.         c_token++;
  1152.         z = real(const_express(&a));
  1153.        }
  1154.        else
  1155.             z = 0;
  1156.        set_position = TRUE;
  1157.     } else {
  1158.        x = y = z = 0;            /* default at origin */
  1159.        set_position = FALSE;
  1160.     }
  1161.  
  1162.     /* get justification */
  1163.     if (!END_OF_COMMAND) {
  1164.        if (set_just)
  1165.         int_error("only one justification is allowed", c_token);
  1166.        if (almost_equals(c_token,"l$eft")) {
  1167.           just = LEFT;
  1168.        }
  1169.        else if (almost_equals(c_token,"c$entre")
  1170.               || almost_equals(c_token,"c$enter")) {
  1171.           just = CENTRE;
  1172.        }
  1173.        else if (almost_equals(c_token,"r$ight")) {
  1174.           just = RIGHT;
  1175.        }
  1176.        else
  1177.         int_error("bad syntax in set label", c_token);
  1178.        c_token++;
  1179.        set_just = TRUE;
  1180.     } 
  1181.  
  1182.     if (!END_OF_COMMAND)
  1183.      int_error("extraenous or out-of-order arguments in set label", c_token);
  1184.  
  1185.     /* OK! add label */
  1186.     if (first_label != NULL) { /* skip to last label */
  1187.        for (this_label = first_label; this_label != NULL ; 
  1188.            prev_label = this_label, this_label = this_label->next)
  1189.         /* is this the label we want? */
  1190.         if (tag <= this_label->tag)
  1191.           break;
  1192.     }
  1193.     if (this_label != NULL && tag == this_label->tag) {
  1194.        /* changing the label */
  1195.        if (set_position) {
  1196.           this_label->x = x;
  1197.           this_label->y = y;
  1198.           this_label->z = z;
  1199.        }
  1200.        if (set_text)
  1201.         (void) strcpy(this_label->text, text);
  1202.        if (set_just)
  1203.         this_label->pos = just;
  1204.     } else {
  1205.        /* adding the label */
  1206.        new_label = (struct text_label *) 
  1207.         alloc ( (unsigned int) sizeof(struct text_label), "label");
  1208.        if (prev_label != NULL)
  1209.         prev_label->next = new_label; /* add it to end of list */
  1210.        else 
  1211.         first_label = new_label; /* make it start of list */
  1212.        new_label->tag = tag;
  1213.        new_label->next = this_label;
  1214.        new_label->x = x;
  1215.        new_label->y = y;
  1216.        new_label->z = z;
  1217.        (void) strcpy(new_label->text, text);
  1218.        new_label->pos = just;
  1219.     }
  1220. }
  1221.  
  1222. /* process 'set nolabel' command */
  1223. /* set nolabel {tag} */
  1224. static void
  1225. set_nolabel()
  1226. {
  1227.     struct value a;
  1228.     struct text_label *this_label;
  1229.     struct text_label *prev_label; 
  1230.     int tag;
  1231.  
  1232.     if (END_OF_COMMAND) {
  1233.        /* delete all labels */
  1234.        while (first_label != NULL)
  1235.         delete_label((struct text_label *)NULL,first_label);
  1236.     }
  1237.     else {
  1238.        /* get tag */
  1239.        tag = (int)real(const_express(&a));
  1240.        if (!END_OF_COMMAND)
  1241.         int_error("extraneous arguments to set nolabel", c_token);
  1242.        for (this_label = first_label, prev_label = NULL;
  1243.            this_label != NULL;
  1244.            prev_label = this_label, this_label = this_label->next) {
  1245.           if (this_label->tag == tag) {
  1246.              delete_label(prev_label,this_label);
  1247.              return;        /* exit, our job is done */
  1248.           }
  1249.        }
  1250.        int_error("label not found", c_token);
  1251.     }
  1252. }
  1253.  
  1254. /* assign a new label tag */
  1255. /* labels are kept sorted by tag number, so this is easy */
  1256. static int                /* the lowest unassigned tag number */
  1257. assign_label_tag()
  1258. {
  1259.     struct text_label *this_label;
  1260.     int last = 0;            /* previous tag value */
  1261.  
  1262.     for (this_label = first_label; this_label != NULL;
  1263.         this_label = this_label->next)
  1264.      if (this_label->tag == last+1)
  1265.        last++;
  1266.      else
  1267.        break;
  1268.     
  1269.     return (last+1);
  1270. }
  1271.  
  1272. /* delete label from linked list started by first_label.
  1273.  * called with pointers to the previous label (prev) and the 
  1274.  * label to delete (this).
  1275.  * If there is no previous label (the label to delete is
  1276.  * first_label) then call with prev = NULL.
  1277.  */
  1278. static void
  1279. delete_label(prev,this)
  1280.     struct text_label *prev, *this;
  1281. {
  1282.     if (this!=NULL)    {        /* there really is something to delete */
  1283.        if (prev!=NULL)        /* there is a previous label */
  1284.         prev->next = this->next; 
  1285.        else                /* this = first_label so change first_label */
  1286.         first_label = this->next;
  1287.        free((char *)this);
  1288.     }
  1289. }
  1290.  
  1291.  
  1292. /* process a 'set arrow' command */
  1293. /* set arrow {tag} {from x,y} {to x,y} {{no}head} */
  1294. static void
  1295. set_arrow()
  1296. {
  1297.     struct value a;
  1298.     struct arrow_def *this_arrow = NULL;
  1299.     struct arrow_def *new_arrow = NULL;
  1300.     struct arrow_def *prev_arrow = NULL;
  1301.     double sx, sy, sz;
  1302.     double ex, ey, ez;
  1303.     int tag;
  1304.     BOOLEAN set_start, set_end, head = 1;
  1305.  
  1306.     /* get tag */
  1307.     if (!END_OF_COMMAND 
  1308.        && !equals(c_token, "from")
  1309.        && !equals(c_token, "to")) {
  1310.        /* must be a tag expression! */
  1311.        tag = (int)real(const_express(&a));
  1312.        if (tag <= 0)
  1313.         int_error("tag must be > zero", c_token);
  1314.     } else
  1315.      tag = assign_arrow_tag(); /* default next tag */
  1316.      
  1317.     /* get start position */
  1318.     if (!END_OF_COMMAND && equals(c_token, "from")) {
  1319.        c_token++;
  1320.        if (END_OF_COMMAND)
  1321.         int_error("start coordinates expected", c_token);
  1322.        /* get coordinates */
  1323.        sx = real(const_express(&a));
  1324.        if (!equals(c_token,","))
  1325.         int_error("',' expected",c_token);
  1326.        c_token++;
  1327.        sy = real(const_express(&a));
  1328.        if (equals(c_token,",")) {
  1329.         c_token++;
  1330.         sz = real(const_express(&a));
  1331.        }
  1332.        else
  1333.            sz = 0;
  1334.        set_start = TRUE;
  1335.     } else {
  1336.        sx = sy = sz = 0;            /* default at origin */
  1337.        set_start = FALSE;
  1338.     }
  1339.  
  1340.     /* get end position */
  1341.     if (!END_OF_COMMAND && equals(c_token, "to")) {
  1342.        c_token++;
  1343.        if (END_OF_COMMAND)
  1344.         int_error("end coordinates expected", c_token);
  1345.        /* get coordinates */
  1346.        ex = real(const_express(&a));
  1347.        if (!equals(c_token,","))
  1348.         int_error("',' expected",c_token);
  1349.        c_token++;
  1350.        ey = real(const_express(&a));
  1351.        if (equals(c_token,",")) {
  1352.         c_token++;
  1353.         ez = real(const_express(&a));
  1354.        }
  1355.        else
  1356.         ez = 0;
  1357.        set_end = TRUE;
  1358.     } else {
  1359.        ex = ey = ez = 0;            /* default at origin */
  1360.        set_end = FALSE;
  1361.     }
  1362.  
  1363.     /* get start position - what the heck, either order is ok */
  1364.     if (!END_OF_COMMAND && equals(c_token, "from")) {
  1365.        if (set_start)
  1366.         int_error("only one 'from' is allowed", c_token);
  1367.        c_token++;
  1368.        if (END_OF_COMMAND)
  1369.         int_error("start coordinates expected", c_token);
  1370.        /* get coordinates */
  1371.        sx = real(const_express(&a));
  1372.        if (!equals(c_token,","))
  1373.         int_error("',' expected",c_token);
  1374.        c_token++;
  1375.        sy = real(const_express(&a));
  1376.        if (equals(c_token,",")) {
  1377.         c_token++;
  1378.         sz = real(const_express(&a));
  1379.        }
  1380.        else
  1381.            sz = 0;
  1382.        set_start = TRUE;
  1383.     }
  1384.  
  1385.     if (!END_OF_COMMAND && equals(c_token, "nohead")) {
  1386.        c_token++;
  1387.            head = 0;
  1388.     }
  1389.  
  1390.     if (!END_OF_COMMAND && equals(c_token, "head")) {
  1391.        c_token++;
  1392.            head = 1;
  1393.     }
  1394.  
  1395.     if (!END_OF_COMMAND)
  1396.      int_error("extraneous or out-of-order arguments in set arrow", c_token);
  1397.  
  1398.     /* OK! add arrow */
  1399.     if (first_arrow != NULL) { /* skip to last arrow */
  1400.        for (this_arrow = first_arrow; this_arrow != NULL ; 
  1401.            prev_arrow = this_arrow, this_arrow = this_arrow->next)
  1402.         /* is this the arrow we want? */
  1403.         if (tag <= this_arrow->tag)
  1404.           break;
  1405.     }
  1406.     if (this_arrow != NULL && tag == this_arrow->tag) {
  1407.        /* changing the arrow */
  1408.        if (set_start) {
  1409.           this_arrow->sx = sx;
  1410.           this_arrow->sy = sy;
  1411.           this_arrow->sz = sz;
  1412.        }
  1413.        if (set_end) {
  1414.           this_arrow->ex = ex;
  1415.           this_arrow->ey = ey;
  1416.           this_arrow->ez = ez;
  1417.        }
  1418.        this_arrow->head = head;
  1419.     } else {
  1420.        /* adding the arrow */
  1421.        new_arrow = (struct arrow_def *) 
  1422.         alloc ( (unsigned int) sizeof(struct arrow_def), "arrow");
  1423.        if (prev_arrow != NULL)
  1424.         prev_arrow->next = new_arrow; /* add it to end of list */
  1425.        else 
  1426.         first_arrow = new_arrow; /* make it start of list */
  1427.        new_arrow->tag = tag;
  1428.        new_arrow->next = this_arrow;
  1429.        new_arrow->sx = sx;
  1430.        new_arrow->sy = sy;
  1431.        new_arrow->sz = sz;
  1432.        new_arrow->ex = ex;
  1433.        new_arrow->ey = ey;
  1434.        new_arrow->ez = ez;
  1435.        new_arrow->head = head;
  1436.     }
  1437. }
  1438.  
  1439. /* process 'set noarrow' command */
  1440. /* set noarrow {tag} */
  1441. static void
  1442. set_noarrow()
  1443. {
  1444.     struct value a;
  1445.     struct arrow_def *this_arrow;
  1446.     struct arrow_def *prev_arrow; 
  1447.     int tag;
  1448.  
  1449.     if (END_OF_COMMAND) {
  1450.        /* delete all arrows */
  1451.        while (first_arrow != NULL)
  1452.         delete_arrow((struct arrow_def *)NULL,first_arrow);
  1453.     }
  1454.     else {
  1455.        /* get tag */
  1456.        tag = (int)real(const_express(&a));
  1457.        if (!END_OF_COMMAND)
  1458.         int_error("extraneous arguments to set noarrow", c_token);
  1459.        for (this_arrow = first_arrow, prev_arrow = NULL;
  1460.            this_arrow != NULL;
  1461.            prev_arrow = this_arrow, this_arrow = this_arrow->next) {
  1462.           if (this_arrow->tag == tag) {
  1463.              delete_arrow(prev_arrow,this_arrow);
  1464.              return;        /* exit, our job is done */
  1465.           }
  1466.        }
  1467.        int_error("arrow not found", c_token);
  1468.     }
  1469. }
  1470.  
  1471. /* assign a new arrow tag */
  1472. /* arrows are kept sorted by tag number, so this is easy */
  1473. static int                /* the lowest unassigned tag number */
  1474. assign_arrow_tag()
  1475. {
  1476.     struct arrow_def *this_arrow;
  1477.     int last = 0;            /* previous tag value */
  1478.  
  1479.     for (this_arrow = first_arrow; this_arrow != NULL;
  1480.         this_arrow = this_arrow->next)
  1481.      if (this_arrow->tag == last+1)
  1482.        last++;
  1483.      else
  1484.        break;
  1485.  
  1486.     return (last+1);
  1487. }
  1488.  
  1489. /* delete arrow from linked list started by first_arrow.
  1490.  * called with pointers to the previous arrow (prev) and the 
  1491.  * arrow to delete (this).
  1492.  * If there is no previous arrow (the arrow to delete is
  1493.  * first_arrow) then call with prev = NULL.
  1494.  */
  1495. static void
  1496. delete_arrow(prev,this)
  1497.     struct arrow_def *prev, *this;
  1498. {
  1499.     if (this!=NULL)    {        /* there really is something to delete */
  1500.        if (prev!=NULL)        /* there is a previous arrow */
  1501.         prev->next = this->next; 
  1502.        else                /* this = first_arrow so change first_arrow */
  1503.         first_arrow = this->next;
  1504.        free((char *)this);
  1505.     }
  1506. }
  1507.  
  1508.  
  1509. enum PLOT_STYLE            /* not static; used by command.c */
  1510. get_style()
  1511. {
  1512. register enum PLOT_STYLE ps;
  1513.  
  1514.     c_token++;
  1515.     if (almost_equals(c_token,"l$ines"))
  1516.         ps = LINES;
  1517.     else if (almost_equals(c_token,"i$mpulses"))
  1518.         ps = IMPULSES;
  1519.     else if (almost_equals(c_token,"p$oints"))
  1520.         ps = POINTS;
  1521.     else if (almost_equals(c_token,"linesp$oints"))
  1522.         ps = LINESPOINTS;
  1523.     else if (almost_equals(c_token,"d$ots"))
  1524.         ps = DOTS;
  1525.     else if (almost_equals(c_token,"e$rrorbars"))
  1526.         ps = ERRORBARS;
  1527.     else
  1528.         int_error("expecting 'lines', 'points', 'linespoints', 'dots', 'impulses', or 'errorbars'",c_token);
  1529.     c_token++;
  1530.     return(ps);
  1531. }
  1532.  
  1533. /* For set [xy]tics... command*/
  1534. static void
  1535. load_tics(tdef)
  1536.     struct ticdef *tdef;    /* change this ticdef */
  1537. {
  1538.     if (equals(c_token,"(")) { /* set : TIC_USER */
  1539.        c_token++;
  1540.        load_tic_user(tdef);
  1541.     } else {                /* series : TIC_SERIES */
  1542.        load_tic_series(tdef);
  1543.     }
  1544. }
  1545.  
  1546. /* load TIC_USER definition */
  1547. /* (tic[,tic]...)
  1548.  * where tic is ["string"] value
  1549.  * Left paren is already scanned off before entry.
  1550.  */
  1551. static void
  1552. load_tic_user(tdef)
  1553.     struct ticdef *tdef;
  1554. {
  1555.     struct ticmark *list = NULL; /* start of list */
  1556.     struct ticmark *last = NULL; /* end of list */
  1557.     struct ticmark *tic = NULL; /* new ticmark */
  1558.     char temp_string[MAX_LINE_LEN];
  1559.     struct value a;
  1560.  
  1561.     while (!END_OF_COMMAND) {
  1562.        /* parse a new ticmark */
  1563.        tic = (struct ticmark *)alloc(sizeof(struct ticmark), (char *)NULL);
  1564.        if (tic == (struct ticmark *)NULL) {
  1565.           free_marklist(list);
  1566.           int_error("out of memory for tic mark", c_token);
  1567.        }
  1568.  
  1569.        /* has a string with it? */
  1570.        if (isstring(c_token)) {
  1571.           quote_str(temp_string,c_token);
  1572.           tic->label = alloc((unsigned int)strlen(temp_string)+1, "tic label");
  1573.           (void) strcpy(tic->label, temp_string);
  1574.           c_token++;
  1575.        } else
  1576.         tic->label = NULL;
  1577.  
  1578.        /* in any case get the value */
  1579.        tic->position = real(const_express(&a));
  1580.        tic->next = NULL;
  1581.  
  1582.        /* append to list */
  1583.        if (list == NULL)
  1584.         last = list = tic;    /* new list */
  1585.        else {                /* append to list */
  1586.           last->next = tic;
  1587.           last = tic;
  1588.        }
  1589.  
  1590.        /* expect "," or ")" here */
  1591.        if (!END_OF_COMMAND && equals(c_token, ","))
  1592.         c_token++;        /* loop again */
  1593.        else
  1594.         break;            /* hopefully ")" */
  1595.     }
  1596.     
  1597.     if (END_OF_COMMAND || !equals(c_token, ")")) {
  1598.        free_marklist(list);
  1599.        int_error("expecting right parenthesis )", c_token);
  1600.     }
  1601.     c_token++;
  1602.     
  1603.     /* successful list */
  1604.     if (tdef->type == TIC_USER) {
  1605.        /* remove old list */
  1606.         /* VAX Optimiser was stuffing up following line. Turn Optimiser OFF */
  1607.        free_marklist(tdef->def.user);
  1608.        tdef->def.user = NULL;
  1609.     }
  1610.     tdef->type = TIC_USER;
  1611.     tdef->def.user = list;
  1612. }
  1613.  
  1614. static void
  1615. free_marklist(list)
  1616.     struct ticmark *list;
  1617. {
  1618.     register struct ticmark *freeable;
  1619.  
  1620.     while (list != NULL) {
  1621.        freeable = list;
  1622.        list = list->next;
  1623.        if (freeable->label != NULL)
  1624.         free( (char *)freeable->label );
  1625.        free( (char *)freeable );
  1626.     }
  1627. }
  1628.  
  1629. /* load TIC_SERIES definition */
  1630. /* start,incr[,end] */
  1631. static void
  1632. load_tic_series(tdef)
  1633.     struct ticdef *tdef;
  1634. {
  1635.     double start, incr, end;
  1636.     struct value a;
  1637.     int incr_token;
  1638.  
  1639.     start = real(const_express(&a));
  1640.     if (!equals(c_token, ","))
  1641.      int_error("expecting comma to separate start,incr", c_token);
  1642.     c_token++;
  1643.  
  1644.     incr_token = c_token;
  1645.     incr = real(const_express(&a));
  1646.  
  1647.     if (END_OF_COMMAND)
  1648.      end = VERYLARGE;
  1649.     else {
  1650.        if (!equals(c_token, ","))
  1651.         int_error("expecting comma to separate incr,end", c_token);
  1652.        c_token++;
  1653.  
  1654.        end = real(const_express(&a));
  1655.     }
  1656.     if (!END_OF_COMMAND)
  1657.      int_error("tic series is defined by start,increment[,end]", 
  1658.              c_token);
  1659.     
  1660.     if (start < end && incr <= 0)
  1661.      int_error("increment must be positive", incr_token);
  1662.     if (start > end && incr >= 0)
  1663.      int_error("increment must be negative", incr_token);
  1664.     if (start > end) {
  1665.        /* put in order */
  1666.         double numtics;
  1667.         numtics = floor( (end*(1+SIGNIF) - start)/incr );
  1668.         end = start;
  1669.         start = end + numtics*incr;
  1670.         incr = -incr;
  1671. /*
  1672.        double temp = start;
  1673.        start = end;
  1674.        end = temp;
  1675.        incr = -incr;
  1676.  */
  1677.     }
  1678.  
  1679.     if (tdef->type == TIC_USER) {
  1680.        /* remove old list */
  1681.         /* VAX Optimiser was stuffing up following line. Turn Optimiser OFF */
  1682.        free_marklist(tdef->def.user);
  1683.        tdef->def.user = NULL;
  1684.     }
  1685.     tdef->type = TIC_SERIES;
  1686.     tdef->def.series.start = start;
  1687.     tdef->def.series.incr = incr;
  1688.     tdef->def.series.end = end;
  1689. }
  1690.  
  1691. static void
  1692. load_offsets (a, b, c, d)
  1693. double *a,*b, *c, *d;
  1694. {
  1695. struct value t;
  1696.  
  1697.     *a = real (const_express(&t));  /* loff value */
  1698.     c_token++;
  1699.     if (equals(c_token,","))
  1700.         c_token++;
  1701.     if (END_OF_COMMAND) 
  1702.         return;
  1703.  
  1704.     *b = real (const_express(&t));  /* roff value */
  1705.     c_token++;
  1706.     if (equals(c_token,","))
  1707.         c_token++;
  1708.     if (END_OF_COMMAND) 
  1709.         return;
  1710.  
  1711.     *c = real (const_express(&t));  /* toff value */
  1712.     c_token++;
  1713.     if (equals(c_token,","))
  1714.         c_token++;
  1715.     if (END_OF_COMMAND) 
  1716.         return;
  1717.  
  1718.     *d = real (const_express(&t));  /* boff value */
  1719.     c_token++;
  1720. }
  1721.  
  1722.  
  1723. BOOLEAN                    /* TRUE if a or b were changed */
  1724. load_range(a,b)            /* also used by command.c */
  1725. double *a,*b;
  1726. {
  1727. struct value t;
  1728. BOOLEAN changed = FALSE;
  1729.  
  1730.     if (equals(c_token,"]"))
  1731.         return(FALSE);
  1732.     if (END_OF_COMMAND) {
  1733.         int_error("starting range value or ':' or 'to' expected",c_token);
  1734.     } else if (!equals(c_token,"to") && !equals(c_token,":"))  {
  1735.         *a = real(const_express(&t));
  1736.         changed = TRUE;
  1737.     }    
  1738.     if (!equals(c_token,"to") && !equals(c_token,":"))
  1739.         int_error("':' or keyword 'to' expected",c_token);
  1740.     c_token++;
  1741.     if (!equals(c_token,"]")) {
  1742.         *b = real(const_express(&t));
  1743.         changed = TRUE;
  1744.      }
  1745.      return(changed);
  1746. }
  1747.  
  1748.  
  1749.  
  1750. /******* The 'show' command *******/
  1751. void
  1752. show_command()
  1753. {
  1754.     c_token++;
  1755.  
  1756.     if (!show_one() && !show_two())
  1757.     int_error(
  1758.     "valid show options:  'action_table', 'all', 'angles', 'arrow', \n\
  1759.     'autoscale', 'border', 'clip', 'contour', 'data', 'dummy', 'format', \n\
  1760.     'function', 'grid', 'key', 'label', 'logscale', 'mapping', 'offsets', \n\
  1761.     'output', 'plot', 'parametric', 'polar', 'rrange', 'samples', \n\
  1762.     'isosamples', 'view', 'size', 'terminal', 'tics', 'ticslevel', \n\
  1763.     'time', 'title', 'trange', 'urange', 'vrange', 'variables', \n\
  1764.     'version', 'xlabel', 'xrange', 'xtics', 'xzeroaxis', 'ylabel', \n\
  1765.     'yrange', 'ytics', 'yzeroaxis', 'zlabel', 'zrange', 'ztics', 'zero', \n\
  1766.     'zeroaxis'", c_token);
  1767.     screen_ok = FALSE;
  1768.     (void) putc('\n',stderr);
  1769. }
  1770.  
  1771. /* return TRUE if a command match, FALSE if not */
  1772. static BOOLEAN
  1773. show_one()
  1774. {
  1775.     if (almost_equals(c_token,"ac$tion_table") ||
  1776.              equals(c_token,"at") ) {
  1777.         c_token++; 
  1778.         show_at();
  1779.         c_token++;
  1780.     }
  1781.     else if (almost_equals(c_token,"ar$row")) {
  1782.         struct value a;
  1783.         int tag = 0;
  1784.  
  1785.         c_token++;
  1786.         if (!END_OF_COMMAND) {
  1787.            tag = (int)real(const_express(&a));
  1788.            if (tag <= 0)
  1789.             int_error("tag must be > zero", c_token);
  1790.         }
  1791.  
  1792.         (void) putc('\n',stderr);
  1793.         show_arrow(tag);
  1794.     }
  1795.     else if (almost_equals(c_token,"au$toscale")) {
  1796.         (void) putc('\n',stderr);
  1797.         show_autoscale();
  1798.         c_token++;
  1799.     }
  1800.     else if (almost_equals(c_token,"bor$der")) {
  1801.         (void) putc('\n',stderr);
  1802.         show_border();
  1803.         c_token++;
  1804.     }
  1805.     else if (almost_equals(c_token,"c$lip")) {
  1806.         (void) putc('\n',stderr);
  1807.         show_clip();
  1808.         c_token++;
  1809.     }
  1810.     else if (almost_equals(c_token,"ma$pping")) {
  1811.         (void) putc('\n',stderr);
  1812.         show_mapping();
  1813.         c_token++;
  1814.     }
  1815.     else if (almost_equals(c_token,"co$ntour")) {
  1816.         (void) putc('\n',stderr);
  1817.         show_contour();
  1818.         c_token++;
  1819.     }
  1820.     else if (almost_equals(c_token,"d$ata")) {
  1821.         c_token++;
  1822.         if (!almost_equals(c_token,"s$tyle"))
  1823.             int_error("expecting keyword 'style'",c_token);
  1824.         (void) putc('\n',stderr);
  1825.         show_style("data",data_style);
  1826.         c_token++;
  1827.     }
  1828.     else if (almost_equals(c_token,"d$ummy")) {
  1829.           (void) fprintf(stderr,"\n\tdummy variables are \"%s\" and \"%s\"\n",
  1830.                         dummy_var[0], dummy_var[1]);
  1831.         c_token++;
  1832.     }
  1833.     else if (almost_equals(c_token,"fo$rmat")) {
  1834.         show_format();
  1835.         c_token++;
  1836.     }
  1837.     else if (almost_equals(c_token,"f$unctions")) {
  1838.         c_token++;
  1839.         if (almost_equals(c_token,"s$tyle"))  {
  1840.             (void) putc('\n',stderr);
  1841.             show_style("functions",func_style);
  1842.             c_token++;
  1843.         }
  1844.         else
  1845.             show_functions();
  1846.     }
  1847.     else if (almost_equals(c_token,"lo$gscale")) {
  1848.         (void) putc('\n',stderr);
  1849.         show_logscale();
  1850.         c_token++;
  1851.     }
  1852.     else if (almost_equals(c_token,"of$fsets")) {
  1853.         (void) putc('\n',stderr);
  1854.         show_offsets();
  1855.         c_token++;
  1856.     }
  1857.     else if (almost_equals(c_token,"o$utput")) {
  1858.         (void) putc('\n',stderr);
  1859.         show_output();
  1860.         c_token++;
  1861.     }
  1862.     else if (almost_equals(c_token,"tit$le")) {
  1863.         (void) putc('\n',stderr);
  1864.         show_title();
  1865.         c_token++;
  1866.     }
  1867.     else if (almost_equals(c_token,"xl$abel")) {
  1868.         (void) putc('\n',stderr);
  1869.         show_xlabel();
  1870.         c_token++;
  1871.     }
  1872.     else if (almost_equals(c_token,"yl$abel")) {
  1873.         (void) putc('\n',stderr);
  1874.         show_ylabel();
  1875.         c_token++;
  1876.     }
  1877.     else if (almost_equals(c_token,"zl$abel")) {
  1878.         (void) putc('\n',stderr);
  1879.         show_zlabel();
  1880.         c_token++;
  1881.     }
  1882.     else if (almost_equals(c_token,"xzero$axis")) {
  1883.         (void) putc('\n',stderr);
  1884.         show_xzeroaxis();
  1885.         c_token++;
  1886.     }
  1887.     else if (almost_equals(c_token,"yzero$axis")) {
  1888.         (void) putc('\n',stderr);
  1889.         show_yzeroaxis();
  1890.         c_token++;
  1891.     }
  1892.     else if (almost_equals(c_token,"zeroa$xis")) {
  1893.         (void) putc('\n',stderr);
  1894.         show_xzeroaxis();
  1895.         show_yzeroaxis();
  1896.         c_token++;
  1897.     }
  1898.     else if (almost_equals(c_token,"la$bel")) {
  1899.         struct value a;
  1900.         int tag = 0;
  1901.  
  1902.         c_token++;
  1903.         if (!END_OF_COMMAND) {
  1904.            tag = (int)real(const_express(&a));
  1905.            if (tag <= 0)
  1906.             int_error("tag must be > zero", c_token);
  1907.         }
  1908.  
  1909.         (void) putc('\n',stderr);
  1910.         show_label(tag);
  1911.     }
  1912.     else if (almost_equals(c_token,"g$rid")) {
  1913.         (void) putc('\n',stderr);
  1914.         show_grid();
  1915.         c_token++;
  1916.     }
  1917.     else if (almost_equals(c_token,"k$ey")) {
  1918.         (void) putc('\n',stderr);
  1919.         show_key();
  1920.         c_token++;
  1921.     }
  1922.     else
  1923.         return (FALSE);
  1924.     return TRUE;
  1925. }
  1926.  
  1927. /* return TRUE if a command match, FALSE if not */
  1928. static BOOLEAN
  1929. show_two()
  1930. {
  1931.     if (almost_equals(c_token,"p$lot")) {
  1932.         (void) putc('\n',stderr);
  1933.         show_plot();
  1934.         c_token++;
  1935.     }
  1936.     else if (almost_equals(c_token,"par$ametric")) {
  1937.         (void) putc('\n',stderr);
  1938.         show_parametric();
  1939.         c_token++;
  1940.     }
  1941.     else if (almost_equals(c_token,"pol$ar")) {
  1942.         (void) putc('\n',stderr);
  1943.         show_polar();
  1944.         c_token++;
  1945.     }
  1946.     else if (almost_equals(c_token,"an$gles")) {
  1947.         (void) putc('\n',stderr);
  1948.         show_angles();
  1949.         c_token++;
  1950.     }
  1951.     else if (almost_equals(c_token,"ti$cs")) {
  1952.         (void) putc('\n',stderr);
  1953.         show_tics(TRUE,TRUE,TRUE);
  1954.         c_token++;
  1955.     }
  1956.     else if (almost_equals(c_token,"tim$e")) {
  1957.         (void) putc('\n',stderr);
  1958.         show_time();
  1959.         c_token++;
  1960.     }
  1961.     else if (almost_equals(c_token,"su$rface")) {
  1962.         (void) putc('\n',stderr);
  1963.         show_surface();
  1964.         c_token++;
  1965.     }
  1966.     else if (almost_equals(c_token,"xti$cs")) {
  1967.         show_tics(TRUE,FALSE,FALSE);
  1968.         c_token++;
  1969.     }
  1970.     else if (almost_equals(c_token,"yti$cs")) {
  1971.         show_tics(FALSE,TRUE,FALSE);
  1972.         c_token++;
  1973.     }
  1974.     else if (almost_equals(c_token,"zti$cs")) {
  1975.         show_tics(FALSE,FALSE,TRUE);
  1976.         c_token++;
  1977.     }
  1978.     else if (almost_equals(c_token,"sa$mples")) {
  1979.         (void) putc('\n',stderr);
  1980.         show_samples();
  1981.         c_token++;
  1982.     }
  1983.     else if (almost_equals(c_token,"isosa$mples")) {
  1984.         (void) putc('\n',stderr);
  1985.         show_isosamples();
  1986.         c_token++;
  1987.     }
  1988.     else if (almost_equals(c_token,"si$ze")) {
  1989.         (void) putc('\n',stderr);
  1990.         show_size();
  1991.         c_token++;
  1992.     }
  1993.     else if (almost_equals(c_token,"t$erminal")) {
  1994.         (void) putc('\n',stderr);
  1995.         show_term();
  1996.         c_token++;
  1997.     }
  1998.     else if (almost_equals(c_token,"rr$ange")) {
  1999.         (void) putc('\n',stderr);
  2000.         show_range('r',rmin,rmax);
  2001.         c_token++;
  2002.     }
  2003.     else if (almost_equals(c_token,"tr$ange")) {
  2004.         (void) putc('\n',stderr);
  2005.         show_range('t',tmin,tmax);
  2006.         c_token++;
  2007.     }
  2008.     else if (almost_equals(c_token,"ur$ange")) {
  2009.         (void) putc('\n',stderr);
  2010.         show_range('u',umin,umax);
  2011.         c_token++;
  2012.     }
  2013.     else if (almost_equals(c_token,"vi$ew")) {
  2014.         (void) putc('\n',stderr);
  2015.         show_view();
  2016.         c_token++;
  2017.     }
  2018.     else if (almost_equals(c_token,"vr$ange")) {
  2019.         (void) putc('\n',stderr);
  2020.         show_range('v',vmin,vmax);
  2021.         c_token++;
  2022.     }
  2023.     else if (almost_equals(c_token,"v$ariables")) {
  2024.         show_variables();
  2025.         c_token++;
  2026.     }
  2027.     else if (almost_equals(c_token,"ve$rsion")) {
  2028.         show_version();
  2029.         c_token++;
  2030.     }
  2031.     else if (almost_equals(c_token,"xr$ange")) {
  2032.         (void) putc('\n',stderr);
  2033.         show_range('x',xmin,xmax);
  2034.         c_token++;
  2035.     }
  2036.     else if (almost_equals(c_token,"yr$ange")) {
  2037.         (void) putc('\n',stderr);
  2038.         show_range('y',ymin,ymax);
  2039.         c_token++;
  2040.     }
  2041.     else if (almost_equals(c_token,"zr$ange")) {
  2042.         (void) putc('\n',stderr);
  2043.         show_range('z',zmin,zmax);
  2044.         c_token++;
  2045.     }
  2046.     else if (almost_equals(c_token,"z$ero")) {
  2047.         (void) putc('\n',stderr);
  2048.         show_zero();
  2049.         c_token++;
  2050.     }
  2051.     else if (almost_equals(c_token,"a$ll")) {
  2052.         c_token++;
  2053.         show_version();
  2054.         show_autoscale();
  2055.         show_border();
  2056.         show_clip();
  2057.         show_contour();
  2058.         show_mapping();
  2059.           (void) fprintf(stderr,"\tdummy variables are \"%s\" and \"%s\"\n",
  2060.                         dummy_var[0], dummy_var[1]);
  2061.         show_format();
  2062.         show_style("data",data_style);
  2063.         show_style("functions",func_style);
  2064.         show_grid();
  2065.         show_label(0);
  2066.         show_arrow(0);
  2067.         show_key();
  2068.         show_logscale();
  2069.         show_offsets();
  2070.         show_output();
  2071.         show_parametric();
  2072.         show_polar();
  2073.         show_angles();
  2074.         show_samples();
  2075.         show_isosamples();
  2076.         show_view();
  2077.         show_surface();
  2078.         show_size();
  2079.         show_term();
  2080.         show_tics(TRUE,TRUE,TRUE);
  2081.         show_time();
  2082.         if (parametric)
  2083.             if (!is_3d_plot)
  2084.                 show_range('t',tmin,tmax);
  2085.             else {
  2086.                 show_range('u',umin,umax);
  2087.                 show_range('v',vmin,vmax);
  2088.             }
  2089.         if (polar)
  2090.           show_range('r',rmin,rmax);
  2091.         show_range('x',xmin,xmax);
  2092.         show_range('y',ymin,ymax);
  2093.         show_range('z',zmin,zmax);
  2094.         show_title();
  2095.         show_xlabel();
  2096.         show_ylabel();
  2097.         show_zlabel();
  2098.         show_zero();
  2099.         show_plot();
  2100.         show_variables();
  2101.         show_functions();
  2102.         c_token++;
  2103.     }
  2104.     else
  2105.         return (FALSE);
  2106.     return (TRUE);
  2107. }
  2108.  
  2109.  
  2110. /*********** support functions for 'show'  **********/
  2111. static void
  2112. show_style(name,style)
  2113. char name[];
  2114. enum PLOT_STYLE style;
  2115. {
  2116.     fprintf(stderr,"\t%s are plotted with ",name);
  2117.     switch (style) {
  2118.         case LINES: fprintf(stderr,"lines\n"); break;
  2119.         case POINTS: fprintf(stderr,"points\n"); break;
  2120.         case IMPULSES: fprintf(stderr,"impulses\n"); break;
  2121.         case LINESPOINTS: fprintf(stderr,"linespoints\n"); break;
  2122.         case DOTS: fprintf(stderr,"dots\n"); break;
  2123.         case ERRORBARS: fprintf(stderr,"errorbars\n"); break;
  2124.     }
  2125. }
  2126.  
  2127. static void
  2128. show_range(name,min,max)
  2129. char name;
  2130. double min,max;
  2131. {
  2132.     fprintf(stderr,"\t%crange is [%g : %g]\n",name,min,max);
  2133. }
  2134.  
  2135. static void
  2136. show_zero()
  2137. {
  2138.     fprintf(stderr,"\tzero is %g\n",zero);
  2139. }
  2140.  
  2141. static void
  2142. show_offsets()
  2143. {
  2144.     fprintf(stderr,"\toffsets are %g, %g, %g, %g\n",loff,roff,toff,boff);
  2145. }
  2146.  
  2147. static void
  2148. show_border()
  2149. {
  2150.     fprintf(stderr,"\tborder is %sdrawn\n", draw_border ? "" : "not ");
  2151. }
  2152.  
  2153. static void
  2154. show_output()
  2155. {
  2156.     fprintf(stderr,"\toutput is sent to %s\n",outstr);
  2157. }
  2158.  
  2159. static void
  2160. show_samples()
  2161. {
  2162.     fprintf(stderr,"\tsampling rate is %d\n",samples);
  2163. }
  2164.  
  2165. static void
  2166. show_isosamples()
  2167. {
  2168.     fprintf(stderr,"\tiso sampling rate is %d\n",iso_samples);
  2169. }
  2170.  
  2171. static void
  2172. show_surface()
  2173. {
  2174.     fprintf(stderr,"\tsurface is %sdrawn\n", draw_surface ? "" : "not ");
  2175. }
  2176.  
  2177. static void
  2178. show_view()
  2179. {
  2180.     fprintf(stderr,"\tview is %g rot_x, %g rot_z, %g scale, %g scale_z\n",
  2181.         surface_rot_x, surface_rot_z, surface_scale, surface_zscale);
  2182. }
  2183.  
  2184. static void
  2185. show_size()
  2186. {
  2187.     fprintf(stderr,"\tsize is scaled by %g,%g\n",xsize,ysize);
  2188. }
  2189.  
  2190. static void
  2191. show_title()
  2192. {
  2193.     fprintf(stderr,"\ttitle is \"%s\", offset at %d, %d\n",
  2194.         title,title_xoffset,title_yoffset);
  2195. }
  2196.  
  2197. static void
  2198. show_xlabel()
  2199. {
  2200.     fprintf(stderr,"\txlabel is \"%s\", offset at %d, %d\n",
  2201.         xlabel,xlabel_xoffset,xlabel_yoffset);
  2202. }
  2203.  
  2204. static void
  2205. show_ylabel()
  2206. {
  2207.     fprintf(stderr,"\tylabel is \"%s\", offset at %d, %d\n",
  2208.         ylabel,ylabel_xoffset,ylabel_yoffset);
  2209. }
  2210. static void
  2211. show_zlabel()
  2212. {
  2213.     fprintf(stderr,"\tzlabel is \"%s\", offset at %d, %d\n",
  2214.         zlabel,zlabel_xoffset,zlabel_yoffset);
  2215. }
  2216.  
  2217. static void
  2218. show_xzeroaxis()
  2219. {
  2220.     fprintf(stderr,"\txzeroaxis is %s\n",(xzeroaxis)? "ON" : "OFF");
  2221. }
  2222.  
  2223. static void
  2224. show_yzeroaxis()
  2225. {
  2226.     fprintf(stderr,"\tyzeroaxis is %s\n",(yzeroaxis)? "ON" : "OFF");
  2227. }
  2228.  
  2229. static void
  2230. show_label(tag)
  2231.     int tag;                /* 0 means show all */
  2232. {
  2233.     struct text_label *this_label;
  2234.     BOOLEAN showed = FALSE;
  2235.  
  2236.     for (this_label = first_label; this_label != NULL;
  2237.         this_label = this_label->next) {
  2238.        if (tag == 0 || tag == this_label->tag) {
  2239.           showed = TRUE;
  2240.           fprintf(stderr,"\tlabel %d \"%s\" at %g,%g,%g ",
  2241.                 this_label->tag, this_label->text, 
  2242.                 this_label->x, this_label->y, this_label->z);
  2243.           switch(this_label->pos) {
  2244.              case LEFT : {
  2245.                 fprintf(stderr,"left");
  2246.                 break;
  2247.              }
  2248.              case CENTRE : {
  2249.                 fprintf(stderr,"centre");
  2250.                 break;
  2251.              }
  2252.              case RIGHT : {
  2253.                 fprintf(stderr,"right");
  2254.                 break;
  2255.              }
  2256.           }
  2257.           fputc('\n',stderr);
  2258.        }
  2259.     }
  2260.     if (tag > 0 && !showed)
  2261.      int_error("label not found", c_token);
  2262. }
  2263.  
  2264. static void
  2265. show_arrow(tag)
  2266.     int tag;                /* 0 means show all */
  2267. {
  2268.     struct arrow_def *this_arrow;
  2269.     BOOLEAN showed = FALSE;
  2270.  
  2271.     for (this_arrow = first_arrow; this_arrow != NULL;
  2272.         this_arrow = this_arrow->next) {
  2273.        if (tag == 0 || tag == this_arrow->tag) {
  2274.           showed = TRUE;
  2275.           fprintf(stderr,"\tarrow %d from %g,%g,%g to %g,%g,%g%s\n",
  2276.                 this_arrow->tag, 
  2277.                 this_arrow->sx, this_arrow->sy, this_arrow->sz,
  2278.                 this_arrow->ex, this_arrow->ey, this_arrow->ez,
  2279.                 this_arrow->head ? "" : " (nohead)");
  2280.        }
  2281.     }
  2282.     if (tag > 0 && !showed)
  2283.      int_error("arrow not found", c_token);
  2284. }
  2285.  
  2286. static void
  2287. show_grid()
  2288. {
  2289.     fprintf(stderr,"\tgrid is %s\n",(grid)? "ON" : "OFF");
  2290. }
  2291.  
  2292. static void
  2293. show_key()
  2294. {
  2295.     switch (key) {
  2296.         case -1 : 
  2297.             fprintf(stderr,"\tkey is ON\n");
  2298.             break;
  2299.         case 0 :
  2300.             fprintf(stderr,"\tkey is OFF\n");
  2301.             break;
  2302.         case 1 :
  2303.             fprintf(stderr,"\tkey is at %g,%g,%g\n",key_x,key_y,key_z);
  2304.             break;
  2305.     }
  2306. }
  2307.  
  2308. static void
  2309. show_parametric()
  2310. {
  2311.     fprintf(stderr,"\tparametric is %s\n",(parametric)? "ON" : "OFF");
  2312. }
  2313.  
  2314. static void
  2315. show_polar()
  2316. {
  2317.     fprintf(stderr,"\tpolar is %s\n",(polar)? "ON" : "OFF");
  2318. }
  2319.  
  2320. static void
  2321. show_angles()
  2322. {
  2323.     fprintf(stderr,"\tAngles are in ");
  2324.     switch (angles_format) {
  2325.         case ANGLES_RADIANS:
  2326.             fprintf(stderr, "radians\n");
  2327.         break;
  2328.         case ANGLES_DEGREES:
  2329.             fprintf(stderr, "degrees\n");
  2330.         break;
  2331.     }
  2332. }
  2333.  
  2334.  
  2335. static void
  2336. show_tics(showx, showy, showz)
  2337.     BOOLEAN showx, showy, showz;
  2338. {
  2339.     fprintf(stderr,"\ttics are %s, ",(tic_in)? "IN" : "OUT");
  2340.     fprintf(stderr,"\tticslevel is %g\n",ticslevel);
  2341.  
  2342.     if (showx)
  2343.      show_ticdef(xtics, 'x', &xticdef);
  2344.     if (showy)
  2345.      show_ticdef(ytics, 'y', &yticdef);
  2346.     if (showz)
  2347.      show_ticdef(ztics, 'z', &zticdef);
  2348.     screen_ok = FALSE;
  2349. }
  2350.  
  2351. /* called by show_tics */
  2352. static void
  2353. show_ticdef(tics, axis, tdef)
  2354.     BOOLEAN tics;            /* xtics ytics or ztics */
  2355.     char axis;            /* 'x' 'y' or 'z' */
  2356.     struct ticdef *tdef;    /* xticdef yticdef or zticdef */
  2357. {
  2358.     register struct ticmark *t;
  2359.  
  2360.     fprintf(stderr, "\t%c-axis tic labelling is ", axis);
  2361.     if (!tics) {
  2362.        fprintf(stderr, "OFF\n");
  2363.        return;
  2364.     }
  2365.  
  2366.     switch(tdef->type) {
  2367.        case TIC_COMPUTED: {
  2368.           fprintf(stderr, "computed automatically\n");
  2369.           break;
  2370.        }
  2371.        case TIC_SERIES: {
  2372.           if (tdef->def.series.end == VERYLARGE)
  2373.             fprintf(stderr, "series from %g by %g\n", 
  2374.                   tdef->def.series.start, tdef->def.series.incr);
  2375.           else
  2376.             fprintf(stderr, "series from %g by %g until %g\n", 
  2377.                   tdef->def.series.start, tdef->def.series.incr, 
  2378.                   tdef->def.series.end);
  2379.           break;
  2380.        }
  2381.        case TIC_USER: {
  2382.           fprintf(stderr, "list (");
  2383.           for (t = tdef->def.user; t != NULL; t=t->next) {
  2384.              if (t->label)
  2385.                fprintf(stderr, "\"%s\" ", t->label);
  2386.              if (t->next)
  2387.                fprintf(stderr, "%g, ", t->position);
  2388.              else
  2389.                fprintf(stderr, "%g", t->position);
  2390.           }
  2391.           fprintf(stderr, ")\n");
  2392.           break;
  2393.        }
  2394.        default: {
  2395.           int_error("unknown ticdef type in show_ticdef()", NO_CARET);
  2396.           /* NOTREACHED */
  2397.        }
  2398.     }
  2399. }
  2400.  
  2401. static void
  2402. show_time()
  2403. {
  2404.     fprintf(stderr,"\ttime is %s, offset at %d, %d\n",
  2405.         (timedate)? "ON" : "OFF",
  2406.         time_xoffset,time_yoffset);
  2407. }
  2408.  
  2409. static void
  2410. show_term()
  2411. {
  2412.     char *str;
  2413.  
  2414.     fprintf(stderr,"\tterminal type is %s %s\n",
  2415.         term_tbl[term].name, term_options);
  2416. }
  2417.  
  2418. static void
  2419. show_plot()
  2420. {
  2421.     fprintf(stderr,"\tlast plot command was: %s\n",replot_line);
  2422. }
  2423.  
  2424. static void
  2425. show_autoscale()
  2426. {
  2427.     fprintf(stderr,"\tautoscaling is ");
  2428.     if (parametric)
  2429.         if (is_3d_plot)
  2430.             fprintf(stderr,"\tt: %s, ",(autoscale_t)? "ON" : "OFF");
  2431.         else
  2432.             fprintf(stderr,"\tu: %s, v: %s, ",
  2433.                         (autoscale_u)? "ON" : "OFF",
  2434.                         (autoscale_v)? "ON" : "OFF");
  2435.     else fprintf(stderr,"\t");
  2436.  
  2437.     if (polar) fprintf(stderr,"r: %s, ",(autoscale_r)? "ON" : "OFF");
  2438.     fprintf(stderr,"x: %s, ",(autoscale_x)? "ON" : "OFF");
  2439.     fprintf(stderr,"y: %s, ",(autoscale_y)? "ON" : "OFF");
  2440.     fprintf(stderr,"z: %s\n",(autoscale_z)? "ON" : "OFF");
  2441. }
  2442.  
  2443. static void
  2444. show_clip()
  2445. {
  2446.     fprintf(stderr,"\tpoint clip is %s\n",(clip_points)? "ON" : "OFF");
  2447.  
  2448.     if (clip_lines1)
  2449.       fprintf(stderr,
  2450.          "\tdrawing and clipping lines between inrange and outrange points\n");
  2451.     else
  2452.       fprintf(stderr,
  2453.          "\tnot drawing lines between inrange and outrange points\n");
  2454.  
  2455.     if (clip_lines2)
  2456.       fprintf(stderr,
  2457.          "\tdrawing and clipping lines between two outrange points\n");
  2458.     else
  2459.       fprintf(stderr,
  2460.          "\tnot drawing lines between two outrange points\n");
  2461. }
  2462.  
  2463. static void
  2464. show_mapping()
  2465. {
  2466.     fprintf(stderr,"\tmapping for 3-d data is ");
  2467.  
  2468.     switch (mapping3d) {
  2469.         case MAP3D_CARTESIAN:
  2470.             fprintf(stderr,"cartesian\n");
  2471.             break;
  2472.         case MAP3D_SPHERICAL:
  2473.             fprintf(stderr,"spherical\n");
  2474.             break;
  2475.         case MAP3D_CYLINDRICAL:
  2476.             fprintf(stderr,"cylindrical\n");
  2477.             break;
  2478.     }
  2479. }
  2480.  
  2481. static void
  2482. show_contour()
  2483. {
  2484.     fprintf(stderr,"\tcontour for surfaces are %s",
  2485.         (draw_contour)? "drawn" : "not drawn\n");
  2486.  
  2487.     if (draw_contour) {
  2488.             fprintf(stderr, " in %d levels on ", contour_levels);
  2489.         switch (draw_contour) {
  2490.             case CONTOUR_BASE:
  2491.                 fprintf(stderr,"grid base\n");
  2492.                 break;
  2493.             case CONTOUR_SRF:
  2494.                 fprintf(stderr,"surface\n");
  2495.                 break;
  2496.             case CONTOUR_BOTH:
  2497.                 fprintf(stderr,"grid base and surface\n");
  2498.                 break;
  2499.         }
  2500.         switch (contour_kind) {
  2501.             case CONTOUR_KIND_LINEAR:
  2502.                 fprintf(stderr,"\t\tas linear segments\n");
  2503.                 break;
  2504.             case CONTOUR_KIND_CUBIC_SPL:
  2505.                 fprintf(stderr,"\t\tas cubic spline interpolation segments with %d pts\n",
  2506.                     contour_pts);
  2507.                 break;
  2508.             case CONTOUR_KIND_BSPLINE:
  2509.                 fprintf(stderr,"\t\tas bspline approximation segments of order %d with %d pts\n",
  2510.                     contour_order, contour_pts);
  2511.                 break;
  2512.         }
  2513.     }
  2514. }
  2515.  
  2516. static void
  2517. show_format()
  2518. {
  2519.     fprintf(stderr, "\ttic format is x-axis: \"%s\", y-axis: \"%s\", z-axis: \"%s\"\n",
  2520.         xformat, yformat, zformat);
  2521. }
  2522.  
  2523. static void
  2524. show_logscale()
  2525. {
  2526.     char *p;
  2527.  
  2528.     if (log_x && log_y && log_z)
  2529.         fprintf(stderr,"\tlogscaling all x, y and z axes\n");
  2530.     else {
  2531.         p = (log_x && log_y)              /* Look for pairs. */
  2532.              ? "x and y"
  2533.              :  (log_x && log_z)
  2534.                      ? "x and z"
  2535.                      :  (log_y && log_z)
  2536.                      ? "y and z"
  2537.                      : NULL;
  2538.         if (p != NULL)
  2539.             fprintf(stderr,"\tlogscaling both %s axes\n",p);
  2540.         else {
  2541.             if (log_x)
  2542.                 fprintf(stderr,"\tlogscaling x axis\n");
  2543.             if (log_y)
  2544.                 fprintf(stderr,"\tlogscaling y axis\n");
  2545.             if (log_z)
  2546.                 fprintf(stderr,"\tlogscaling z axis\n");
  2547.             if (!(log_x || log_y || log_z))
  2548.                 fprintf(stderr,"\tno logscaling\n");
  2549.         }
  2550.     }
  2551. }
  2552.  
  2553. static void
  2554. show_variables()
  2555. {
  2556. register struct udvt_entry *udv = first_udv;
  2557. int len;
  2558.  
  2559.     fprintf(stderr,"\n\tVariables:\n");
  2560.     while (udv) {
  2561.          len = instring(udv->udv_name, ' ');
  2562.         fprintf(stderr,"\t%-*s ",len,udv->udv_name);
  2563.         if (udv->udv_undef)
  2564.             fputs("is undefined\n",stderr);
  2565.         else {
  2566.             fputs("= ",stderr);
  2567.             disp_value(stderr,&(udv->udv_value));
  2568.             (void) putc('\n',stderr);
  2569.         }
  2570.         udv = udv->next_udv;
  2571.     }
  2572. }
  2573.  
  2574. void                /* used by plot.c */
  2575. show_version()
  2576. {
  2577. extern char version[];
  2578. extern char patchlevel[];
  2579. extern char date[];
  2580. extern char bug_email[];
  2581. static char *authors[] = {"Thomas Williams","Colin Kelley"}; /* primary */
  2582. int x;
  2583. long time();
  2584.  
  2585.     x = time((long *)NULL) & 1;
  2586.     fprintf(stderr,"\n\t%s\n\t%sversion %s\n",
  2587.         PROGRAM, OS, version); 
  2588.     fprintf(stderr,"\tpatchlevel %s\n",patchlevel);
  2589.      fprintf(stderr, "\tlast modified %s\n", date);
  2590.     fprintf(stderr,"\tCopyright (C) 1986, 1987, 1990, 1991  %s, %s\n",
  2591.         authors[x],authors[1-x]);
  2592.     fprintf(stderr, "\n\tSend bugs and comments to %s\n", bug_email);
  2593. }
  2594.  
  2595.  
  2596.  
  2597.  
  2598.  
  2599.  
  2600.  
  2601.  
  2602.